#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <functional>
#include <string>
#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"

using namespace std;

namespace ThreadNS
{
    const int defaultnum = 5;

    class ThreadData
    {
    public:
        ThreadData(const string &name) : threadname(name)
        {
        }
        ~ThreadData()
        {
        }

    public:
        const string threadname;
    };

    template <class T>
    class ThreadPool
    {
    private:
        ThreadPool(int thread_num = defaultnum) : _thread_num(thread_num)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);

            // 构建若干个线程

            for (int i = 0; i < _thread_num; i++)
            {
                // 待优化
                string threadname = "thread-";
                threadname += to_string(i + 1);

                ThreadData td(threadname);
                // 把方法绑给了线程
                //  Thread<ThreadData> t(threadname,
                //           bind(&ThreadPool<T>::ThreadRun,this,placeholders::_1),
                //          td);

                // _threads.push_back(t);

                _threads.emplace_back(threadname,
                                      bind(&ThreadPool<T>::ThreadRun, this,
                                           placeholders::_1),
                                      td);
                lg.LogMessage(Info, "%s is created ...\n", threadname.c_str());
            }
        }
        ThreadPool(const ThreadPool<T> &tp) = delete;
        const ThreadPool<T> &operator=(const ThreadPool<T>) = delete;

    public:
        static ThreadPool<T> *GetInstance()
        {
            if (instance == nullptr) // 双if判断的方式，来对后来的线程拦截（不用再进来申请锁判断了）
            {
                LockGuard lockguard(&sig_lock);

                if (instance == nullptr)
                {
                    lg.LogMessage(Info, "创建单例成功...\n");
                    instance = new ThreadPool<T>();
                }
            }

            return instance;
        }

        void checkSelf()
        {
            // 如果任务多了线程少了那么需要增加线程
            if (_task_num >= _task_water_high && _thread_num < _thread_water_high)
            {
                for (int i = _thread_num; i <= _thread_water_high; i++)
                {
                    // 待优化
                    string threadname = "thread-";
                    threadname += to_string(i + 1);

                    ThreadData td(threadname);
                    _threads.emplace_back(threadname,
                                          bind(&ThreadPool<T>::ThreadRun, this,
                                               placeholders::_1),
                                          td);
                    lg.LogMessage(Info, "%s is created ...\n", threadname.c_str());
                }
                _thread_num = _thread_water_high;
            }

            // 如果线程多了任务少了减少线程
            if (_task_num < _task_water_low && _thread_num > _thread_water_high)
            {
                Wait();
            }
        }
        bool Start()
        {
            // 启动线程
            for (auto &thread : _threads)
            {
                thread.Start(); // 执行初始化时的函数
                lg.LogMessage(Info, "%s is running ...\n", thread.Threadname().c_str());
            }

            return true;
        }
        void ThreadWakeup()
        {
            pthread_cond_signal(&_cond); // 唤醒cond队列中阻塞的一个线程
        }

        void ThreadWait(const ThreadData &td)
        {
            lg.LogMessage(Debug, "no task,%s is sleeping ...\n", td.threadname.c_str());

            pthread_cond_wait(&_cond, &_mutex); // 进行线程等待
        }

        // 线程执行的方法
        void ThreadRun(ThreadData &td)
        {
            while (true)
            {
                sleep(1);
                checkSelf();
                T t;
                {
                    // 取任务
                    LockGuard lockguard(&_mutex);
                    while (_q.empty()) // 若为空则进行等待
                    {
                        ThreadWait(td); // 不断等待直到队列不为空为止
                    }
                    // 出来后表示此时队列中有数据，对此就需要
                    // 进行取出并处理
                    lg.LogMessage(Debug, "thread %s is wakeup\n", td.threadname.c_str());
                    t = _q.front();
                    _q.pop();
                }
                // 处理任务
                // 他属于一个线程私有，所以可以不加锁
                t(); // 调用任务的仿函数
                // lg.LogMessage(Debug, "%s handler task %s done,result is: %s\n", td.threadname.c_str(), t.PrintTask().c_str(), t.PrintResult().c_str());
            }
        }

        void Push(T &in)
        {
            LockGuard lockguard(&_mutex);
            _q.push(in);
            ThreadWakeup();
        }

        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
        }

        // 用来进行测试的
        void Wait()
        {
            for (auto &thread : _threads)
            {
                thread.Join(); // 执行初始化时的函数！！
            }
        }

    private:
        queue<T> _q;
        vector<Thread<ThreadData>> _threads;

        static ThreadPool<T> *instance;
        int _thread_num;
        int _task_num;

        int _task_water_low;
        int _task_water_high;
        int _thread_water_low;
        int _thread_water_high;

        pthread_mutex_t _mutex;
        static pthread_mutex_t sig_lock;
        pthread_cond_t _cond;
    };

    template <class T>
    ThreadPool<T> *ThreadPool<T>::instance = nullptr;

    template <class T>
    pthread_mutex_t ThreadPool<T>::sig_lock = PTHREAD_MUTEX_INITIALIZER;
    // pthread_mutex_initializer
}
